/*
 *      mastermind.cpp
 *      
 *      Copyright 2008 Marshall <marshall@marshall-laptop>
 *      
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 *      Marshall Conover, November 2008 - Mastermind Program
 */

#include <iostream>
#include <iomanip>
#include <ctime>
#include <cstdlib>
#include <cstring>
using namespace std;

//Variables 
//----------------------------------------------------------------------------------
int turns=0; // used to keep track of the number of turns that have passed.
int blank=0; //One of the two numbers the player isn't using
bool FoundIt=0; // Tells me when I've found one of the two unused numbers
int usercode[4]; // The user's secret code
int compcode[4]; // The computer's secret code
bool GameEnder=0;  //if a user wins, this variable is set to 1. 
int PrevGuessH[100][4]; //This variable will hold the previous guesses of the Human.
bool WhoWon=0; //Keeps track of who won The Game
bool usedComp[4][7]; //keeps track of which numbers for the computer are not black pegs
bool usedlikely[4][7]; //keeps track of which numbers for the computer might be black pegs
int blankfinder=0; //used to look for the blank number
//Functions
//----------------------------------------------------------------------------------
bool GuessCorrect(int guess[])
{ 
   for (int counter=0;counter<4;counter++) //check to see if the code is workable
   {
   		if (guess[counter] >6 or guess[counter]<1) //if their code contains a number that doesn't work
    	{
    		cout << "Oops, that code has a number that isn't between 1 and 6! Please try another. "<< endl << endl;
    	    return 1;
    	    counter=4; //makes sure the loop exits, so you don't get multiple error messages.
    	}
	} 
    	
    return 0; //Code works.
		
}
//----------------------------------------------------------------------------------
int GuessCheck(bool ManOrComp, int guess[])
{
	int counter=0;  //my counting variable
	int counter2=0;  //my second counting variable
	int pegs[2]={0,0}; //first are the black pegs, second are the white.
	int used[7]={0,0,0,0,0,0,0}; //this keeps track of what numbers already have pegs; 1 is used, 0 is not used.
	if (ManOrComp==0) //if it's a man, baby
	{
		for (counter=0;counter<4;counter++) 
		{
			used[compcode[counter]]++;
		} 
		for (counter=0;counter<4;counter++) //Check for black pegs, and remember which #'s are used.
		{
			if (guess[counter]==compcode[counter]) //if the user's guess is exatcly the comp's code  
			{
				pegs[0]++; // add 1 to the black pegs
				used[compcode[counter]]--; // set the number to used
			}
		} 
	    for (counter=0;counter<4;counter++)
	    {
			for (counter2=0;counter2<4;counter2++)
			{
				if (guess[counter]==compcode[counter2] and used[guess[counter]] >0) //if the user's guess is somewhere in the comp's code  
				{
					pegs[1]++; // add 1 to white pegs
					used[compcode[counter2]]--; //set number to used
				}
			}
		}
//		for (counter=0; counter<4; counter++) cout << compcode[counter]; // prints the comp's code; used to see if the peg counts are right.
		cout << "You get " << pegs[0] << " black pegs, and " << pegs[1] << " white pegs.";
		if (pegs[0]==4)
		{
			cout << endl <<" YOU WIN!" << endl;
cout << endl << "                                                                m.e>                      " << endl;      
cout << "	                                            .      :$M~ u@R8'"                         << endl;
cout << "	                                            !~bx++@MMN@RMM6                           "<< endl;
cout << "	                            :@$ .oW$$$$$bu  F~~~XRMMMMMMMZ~~~%x                       "<< endl;
cout << "	                          x$$$@$$$$$$$$$u  M~~~XRMMMMMMM@RRMMMMR$o.   ....            "<< endl;
cout << "	                 '*$$$$$$$$$$$$$$$$$$$$$$$W!~~~MMMMMMMMMMMMMMMMMMMM!~~~~~~~~~'?+x  ..."<< endl;
cout << "	                .d$$$$$$$$$$$$$$$$$$$$$$$$$$L~~MMMMMMMMMMMMMMMMMMMM$@RRR~~~~~~~~~~~~>X"<< endl;
cout << "	              .$$$$$$$$$$$$$$$$!?#$$$$$$$$$$$!~~N888888@**#TTT*MMMMMMMF~~~~~~~~~~~~!F "<< endl;
cout << "	             d$$$$$$$$$$$$$$$$$E!!!!$$$$$$$$$$~tX!!!!!!!!!!!!tRMMMMMMMRNi+#'~~~~~~W!! "<< endl;
cout << "	            d$$$$$$$$$$$$$$$$!!!!!!!!@$$$$$$$$l!!!!!XH!!!!!!?T?@MMMMM$T)uu~~~~~~~M9~! "<< endl;
cout << "	             $$$$$$$$$$$$$$$$!!!!!!!!!$$$$$$%P    ?**XX!!!!!!XRMMMMMMM!~~~~~~~~~(fX!> "<< endl;
cout << "	            ($$$$$$$$$$$$$$$E!!!L`'4U@$$$$$$!?. z+>     '*!!XRMMMMMMMM!~~~~~~~~~M!$t  "<< endl;
cout << "	            M$$$$$$$$$EM?$$$!!!!?:   '#$$$$F@TT!!!!*     d!XR88MMMMMM5L~~~~~~~~~X!%R  "<< endl;
cout << "	            9$$$$$$$$$$U!!M$!!!!!!Tx   $$$$b*UUX!!!!?%!?!!!MR!@!R8@#!!!!!T%u~~~t~WX   "<< endl;
cout << "	            d$$$$$$$$$$%!!!!!!!!!!!?N!$$$#!!!!!!!!!!!!!!!!!?!?!XM!!!!!!!!!!!!?tKX?@+. "<< endl;
cout << "	           @$$$$$$#?!Tt!!!!!!!XX!!!UU$$$$$@@@HUUXXXH=WI$W!!!M'*X!!!!!!!!!!!!!!!!Rt~~~~"<< endl;
cout << "	         z$$$$$$?!!!!!!?W!!!!MMNX?U!!$$$E!!9~~~~~?R$$$$$%!!!?~~~'4!!!!!U@!!!!!!!!?L~~~"<< endl;
cout << "	       x$$$$$$$!!!!!!!!!!R!!W$$$$$$W$$$$!!!!%i:~X?$$$*T!!!!?~~~~~~~9@?!!!!!!!!!!!!M~~~"<< endl;
cout << "	     x$$$$$$$$!!!!!!!!!!!!N$$$$$$$$$$$$$!!!!!!!?%U!!!!!!!!!?~:umM?!!!!!!!!!!!!!!!H'~~~"<< endl;
cout << "	    dP?$$$$$$?!!!!!!!!!!!!!M$$$$$$$$R!!M!XHS$!U@@#X!!!!!!X@?!!!!!!!!!!!!!!!!!!!X#!~~~~"<< endl;
cout << "	     :$$$$$$%!!!!!#X!!!!!!!!?$$$$$$$N!!@?XM?!!@?!UH@!!!!!!!!!!!!!!!!!!!!!!!!!X#!!~~~~~"<< endl;
cout << "	    d$$$$*#""#*tX!!?K!!!!!!!!!R$$$!$~B?!t!!!!!!!!X@?!!!!!!!!!!!XUH!!!!!!!!!H5~~~~~~~~~"<< endl;
cout << "	  d$$$$'~~~~~~~~~~%X!RX!!!!!!!!!$B@@TT!!!!!!!!!H?!!!!!!!!!!!!H!!!!!!!!!!H#!?'~~~~~~~~~"<< endl;
cout << "	$$$$$U@**tU!(~~~~~~~?NXN!!!!!!!!!!!!!!!!!!!U@T!!!!!!!!!!!!!!!!!!!!!!!H'~~~~~~~~~~~~~~~"<< endl;
cout << "	#'~~~~~~~~~~'@X:~~~~~~~?#W!!!!!!!!!!!!!!UM!!!!!!!!!!!!!!!!!!!!!!!!U*X!!~~~~~~~~~~~~~~:"<< endl;
cout << "	~~~~~~~~~~~~~~!#U!(:~~~~:!?t!!!!!!!!!XM!!!!!!!!!!!!!!!!!!!!!!!!X*~~~~'%i:~~~~~~~~~~~XF"<< endl;
cout << "	~~~~~~~~~~~~~~!!!!%U!!!!!!!!?t!!UH*'~~?%U!!!!!!!!!!!!!!!!!!!!Xf~~~~~~~~~~~'#%~~~~~~t_z"<< endl;
cout << "	~~~~~~~~~~~~!!!!!!!~~~~~""#*ti:~~~~~~~~~~~?t!!!!!!!!!!!!!!!!M!~~~~~~~~~~~~~~~~~~~~W@!("<< endl;
cout << "	~~~~~~~~~:!!!!!!!!!~~~~~~~~~~~~~#@i:~~~~~~~~~?U!!!!!!!!!!!X#@i!~:~~~~~~~~~~~~~~~~!!~(W"<< endl;
cout << "	~~~~~~:!!!!!!!!~~~~~~~~~~~~~~~~~~~~~?t:~~~~~~~~?t!!!!!!!!@~~~!!!!?*%ii::~~~~~~~~~~(H?!"<< endl;
cout << "	~~~~~!!!~!!!!!!~~~~~~~~~~~~~~~~~~~~~~~~#i~~~~~~~~?X!!!!XF~~~~~~~~~~~!!!!!!!'T##X~?X!!~"<< endl;
cout << "	~!!!!!!~~!!!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~?i~~~~~~~~N!!@~~~~~~~~~~~~~~~~~~~~~~~~!t/W!!~"<< endl;
cout << "	~!~~~!!!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#i~~~~~~~?E~~~~~~~~~~~~~~~~~~~~~~~~~~~'?!!~"<< endl;
cout << "	!!~~~:!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#L!!!:!!!#i~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"<< endl;
cout << "	!!!~~!!!!(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!!%X!~~~~~~~#i:~~~~~~~~~~~~~~~~~~~~~~~~!!"<< endl;
cout << "You are a succesful young man who has a great future in life!" << endl << endl;
			GameEnder=1; //Change the sentinal value of the game loop.
			WhoWon=0; //Human won 
		}
	return 0;
	}
	if (ManOrComp==1) //if it's the computer
	{
		for (counter=0;counter<4;counter++) //Check for black pegs, and remember which #'s are used.
		{
			used[usercode[counter]]++;
		} 
		for (counter=0;counter<4;counter++) //Check for black pegs, and remember which #'s are used.
		{
			if (guess[counter]==usercode[counter]) //if the user's guess is exatcly the comp's code  
			{
				pegs[0]++; // add 1 to the black pegs
				used[usercode[counter]]--; // set the number to used
			}
		} 
	    for (counter=0;counter<4;counter++)
	    {
			for (counter2=0;counter2<4;counter2++)
			{
				if (guess[counter]==usercode[counter2] and used[guess[counter]] >0) //if the user's guess is somewhere in the comp's code  
				{
					pegs[1]++; // add 1 to white pegs
					used[usercode[counter2]]--; //set number to used
				}
			}
		}
	cout << endl << "The Hypnotoad recieves " << pegs[0] << " black pegs, and " << pegs[1] << " white pegs.";
		if (pegs[0]==4)
		{
			cout << " All Glory to the Hypnotoad!" << endl;
			cout <<"	       ,'``.._   ,'``'" << endl;
			cout <<"              :,--._:)\\,:,._,.:       All Glory to" << endl;
			cout <<"              :`--,''   :`...';\\      the HYPNO TOAD!" << endl;	
			cout <<"               `,'       `---'  `."<< endl;
			cout <<"               /                 :"<< endl;
			cout <<"              /                   \\"<< endl;
			cout <<"            ,'                     :\\.___,-."<< endl;
			cout <<"           `...,---'``````-..._    |:      \\"<< endl;
			cout <<"             (                 )   ;:    )  \\  _,-."<< endl;
			cout <<"              `.              (   //          `'   \\"<< endl;
			cout <<"               :               `.//  )      )     , ;"<< endl;
			cout <<"             ,-|`.            _,'/       )    ) ,' ,'"<< endl;
			cout <<"            (  :`.`-..____..=:.-':     .     _,' ,'"<< endl;
			cout <<"             `,'\\ ``--....-)='    `._,  \\  ,') _ '``._"<< endl;
			cout <<"          _.-/ _ `.       (_)      /     )' ; / \\ \\`-.'"<< endl;
			cout <<"         `--(   `-:`.     `' ___..'  _,-'   |/   `.)"<< endl;
			cout <<"             `-. `.`.``-----``--,  .'"<< endl;
			cout <<"               |/`.\\`'        ,','); SSt"<< endl;
			cout <<"                   `         (/  (/"<< endl;
			GameEnder=1; //Change the sentinal value of the game loop.
			WhoWon=1; //Computer Won
		}
		if (pegs[0]==0 && pegs[1]==0)
	    {
	    	FoundIt=1;
	    	blank = guess[1];
	    	for (int x=0;x<4;x++)
	    	{
	    		usedComp[x][guess[x]]=1; //holds the fact that that number 
	    		                        //is not a black peg 
			}
		}
		if (pegs[0]==0)
		for (int x=0;x<4;x++)
	    	{
	    		usedComp[x][guess[x]]=1; //holds the fact that that number 
	    		                        //is not a black peg 
			}	return 0;
		if (pegs[0]>=2)
		for (int x=0;x<4;x++)
	    	{
	    		usedlikely[x][guess[x]]=1; //holds the fact that that number 
	    		                        // might be a black peg 
			}	return 0;

	}

	return 0; 
}
//----------------------------------------------------------------------------------
bool ManGuess()
{
	int userguess[4];
	int counter=0;
	do
	{
		cout << endl << "What do you think the Hypnotoad's code is? " ;
		if (PrevGuessH[0][0]>0) //If the user had guessed before, print
	    	                    // all of his guesses.
		{
			cout << "Your previous guesses are: " << endl;
			for (int counter=0; counter<99; counter++) //run through all of the spots guesses could be in.
			{
				if (PrevGuessH[counter][0] > 0 ) //if this spot hold a guess, print it
				{
					cout << "| "<< counter+1 << ": "; //Prints which number guess it was
					for (int counter2=0; counter2<4; counter2++) 
					cout << PrevGuessH[counter][counter2] << ", "; //print each part of the array
				}
			}
		}
		cout << endl;
		for (counter=0; counter<4; counter++) 
		{
		  cin >> userguess[counter]; //gets the user's numbers in order.
		}
	}
	while (GuessCorrect(userguess)==1); // If the user's code doesn't return a 1 
	                                    // (fail) from userguess, continue on.
	for	(int x=0;x<4;x++) PrevGuessH[turns][x]=userguess[x]; //records the user's guess
	GuessCheck(0,userguess); //see how close the user is
	return 0;
}
//----------------------------------------------------------------------------------

void setUsedCompZero() //resets the used numbers that have been guesed for a new game
{
	for (int x=0;x<4;x++)
	{
		for (int y=0;y<7;y++) usedComp[x][y]=0;
	}
}

//----------------------------------------------------------------------------------
bool CompuGuess()
{
	if (GameEnder==1) return 0;
	int CompNumbers[4];
	int counter;
	int blackcounter=0;
	blackcounter=0;
	if (blank==0) //if we haven't found an unused number
	{
	blankfinder++;
	for (int counterz=0; counterz<4; counterz++) CompNumbers[counterz]=blankfinder;
	cout << endl << "In his infinite wisdom, the Hypnotoad guesses: " <<CompNumbers[0]<< ", " << CompNumbers[1]
	     << ", "<< CompNumbers[2]<< ", "<<CompNumbers[3] << "." << endl;
	GuessCheck(1,CompNumbers);
	return 0;
	//if a blank number has been found
	}
	for (counter=0;counter<4;counter++) //this loop generates the four
	                                    //#'s, while simultaneously
	                                    //checking that they haven't
	                                    //already been proved false.
	
	{
		
		do
		{
			blackcounter=0;
			do
			{
				CompNumbers[counter]=1+rand() %6;
				blackcounter++;
			}
			while (usedlikely[counter][CompNumbers[counter]]!=1 && blackcounter<2);
		}
		while (usedComp[counter][CompNumbers[counter]]==1); //if the number has been proved
		                              //false, generate another.
	}
	cout <<endl << endl << "Hypnotoad's Turn!";
	cout << endl << "In his infinite wisdom, the Hypnotoad guesses: " <<CompNumbers[0]<< ", " << CompNumbers[1]
	     << ", "<< CompNumbers[2]<< ", "<<CompNumbers[3] << "." << endl;
	GuessCheck(1,CompNumbers);
	return 0;
}
//----------------------------------------------------------------------------------
int GetCode() // Grab the user's code.
{
	int counter=0;
	do
	{
		cout << "What secret code do you want to use? Enter a number between 1 and 6,"<< endl; 
		cout << "then a space, then another number, like this: 1 4 5 6." << endl << endl;
		for (counter=0;counter<4;counter++) // get the code 
		{	
			cin >> usercode[counter]; // gets all four using counter's changing value
		} 
	} 
	while (GuessCorrect(usercode)==1);// If the user's code doesn't return a 1 
	                                  //(fail) from userguess, continue on.
	cout << "So your code is";
	for (int counter5=0;counter5<4;counter5++) //print the code
	{	 
		cout << " " << usercode[counter5]; 
	} 
	cout <<". I'll make sure to keep it quiet." << endl;
	return 0;
}
//----------------------------------------------------------------------------------
int NewGame()
{
	GameEnder=0; //reset GameEnder 
	for	(int x=0;x<100;x++) 
		for (int y=0;y<4;y++) PrevGuessH[x][y]=0; //reset the user's previous guesses
	for (int x=0;x<4;x++) compcode[x]= 1+rand() %6; //create a new computer code
	turns=0;
	setUsedCompZero(); // resets the numbers that the computer knows 
	                   // aren't part of the answer. 
	blankfinder=0;
	blank=0;
	GetCode();
	return 0;
}
//----------------------------------------------------------------------------------
int main(int argc, char** argv)
{ 
	cout << "MMMM     MMMM      AAA      SSSSSSSS   TTTTTTTTTTTT  EEEEEEEE  RRRRR"<< endl;
	cout << "MM MM   MM MM     AA AA    SSSS            TTT       EE        RR  RR"<< endl;
	cout << "MM  MM MM  MM    AAAAAAA    SSSSSSSS       TTT       EEEEEEEE  RRRRR"<< endl;
	cout << "MM   MMM   MM   AA     AA        SSSS      TTT       EE        RR  RR" <<endl;
	cout << "MM    M    MM  AA       AA  SSSSSSSS       TTT       EEEEEEEE  RR   RR"<< endl;
	cout << endl;
	cout << "           MMMM     MMMM  IIIIIIIIIII  NNNN    NN  DDDDD"<< endl;
	cout << "           MM MM   MM MM      III      NN NN   NN  DD  DDD" << endl;
	cout << "           MM  MM MM  MM      III      NN  NN  NN  DD   DDD"<< endl;
	cout << "           MM   MMM   MM      III      NN   NN NN  DD  DDD" <<endl;
	cout << "           MM    M    MM  IIIIIIIIIII  NN    NNNN  DDDDDD"<< endl;
	cout << endl << "                         By Marshall Conover                    " << endl;
	cout << endl; //ASCII ftw
	cout << "The Rules: " << endl
 	     <<"           You play against the Almighty Hypnotoad for your freedom," << endl
	     << "each of you trying to guess each other's special code, which consists " << endl
	     << "of four numbers between 1 and 6. If you have the correct number in " << endl
	     << "the right spot, you will get a black peg; a correct number in the " << endl
	     << "wrong order will get you a white peg. So, if you guess '1,1,2,3', and" << endl
	     << "the answer is '3,3,2,1', you will get back two white pegs, and a black " << endl
	     << "peg. The first to guess the other's number wins!" << endl<<endl;
	for (int x=0;x<4;x++) compcode[x]= 1+rand() %6; //create the computer code
	setUsedCompZero(); //I run this to make sure the values in the bools
					  // start at zero.
	GetCode(); //Get the user's code, which is stored globally
	for (int x=0;x<4;x++)
	{
		for (int y=0;y<7;y++) usedComp[x][y]=0;
	}
	string play="y"; 
	while (play=="y")
	{	
		while (GameEnder==0)
			{
	   		    ManGuess();
				CompuGuess();
				turns++;	
			}
	if (WhoWon==1) cout << "THE ALMIGHTY HYPNOTOAD SHOWS A RARE MOMENT OF MERCY. WILL YOU CHALLENGE HIM AGAIN, OR SUBMIT TO YOUR FATE? (y or n) " << endl;	
	if (WhoWon==0) cout << "Play again?(y or n)"<< endl;
	cin >> play;
	if (play=="y" && GameEnder==1) NewGame();
	}
	return 0;
}
//----------------------------------------------------------------------------------
